feat(security): npm bootstrap path, exact npm pin, and release rulesets - #9
Merged
Conversation
Two gaps OpenSSF Scorecard flagged on the first run (7/10 overall).
Pinned-Dependencies scored 9 rather than 10 because release.yml
installed npm@11, a floating major. Pinned to an exact patch; Renovate
keeps it current.
Added two repository rulesets:
- Release integrity: main requires the CI checks to pass, signed
commits, and blocks deletion and force-push.
- Immutable release tags: refs/tags/v* cannot be deleted, updated,
force-pushed or created unsigned. GitHub's immutable-releases setting
is not exposed through the REST API, and this covers the half that
matters -- a published version tag cannot be repointed at different
code.
This change deliberately goes through a pull request rather than a direct
push. Scorecard scored Code-Review 0 because every commit so far landed
straight on main, and the new ruleset now enforces the better path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEdTd43qLEEE5qCsL1A7gW
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three related changes to the release-security posture.
npm's first publish needs a token — made single-use by construction
npm cannot attach a trusted publisher to a package that does not exist, and there is no way to reserve a name first. So the first publish must authenticate with a token.
The risk isn't the bootstrap, it's the credential quietly becoming permanent. The workflow now refuses the token path once the package exists on npmjs — a release fails while
NPM_TOKENis still present. Cleanup stops being something to remember.All four states are explicit and were tested:
Provenance is unaffected, which is the part worth knowing:
--provenancederives from the job's Sigstore identity viaid-token, not from how npm authenticates.v0.1.0will be fully attested despite predating trusted publishing on the package.Also dropped
registry-urlfromsetup-node. It writes//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}into.npmrc, which resolves to an empty token when no secret is set — that would have made npm attempt token auth instead of falling back to OIDC, breaking every release after the first.Exact npm pin
Scorecard scored
Pinned-Dependencies9/10 becauserelease.ymlinstallednpm@11, a floating major. Now pinned to an exact patch; Renovate keeps it current.Two new rulesets
mainrequires the CI checks to pass and signed commits; no deletion, no force-push.refs/tags/v*cannot be deleted, updated, force-pushed, or created unsigned.The tag ruleset matters because GitHub's immutable-releases setting is not exposed through the REST API. This covers the half that counts: a published version tag cannot be repointed at different code after the fact.
Also the first PR in this repository on purpose — Scorecard scored
Code-Review0 because everything so far landed directly on main, and the new ruleset enforces the better path from here.SECURITY.mddocuments the bootstrap as a four-step procedure, with the token deliberately weak: granular,@matchory-scoped, 7-day expiry, stored as areleaseenvironment secret rather than a repository one so the existing approval andv*-tag gates already apply to it.